#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <time.h>
#include <ctype.h>

#define PORT 10081
#define BUFFER_SIZE 4096
#define DEVICE_ID_LEN 8
#define SERVER_IP "127.0.0.1"

// 全局变量
int sockfd;
struct sockaddr_in server_addr;
socklen_t server_len = sizeof(server_addr);
char device_id[20];
int device_role = -1;
int running = 1;

// 比较函数，用于qsort排序
int compare_int(const void *a, const void *b) {
    return (*(int *)a - *(int *)b);
}

char *strdup(const char *s) {
    if (s == NULL) {
        return NULL;
    }
    
    // 计算字符串长度（包含终止符'\0'）
    size_t len = strlen(s) + 1;
    
    // 分配内存
    char *copy = (char *)malloc(len);
    if (copy == NULL) {
        return NULL;  // 内存分配失败
    }
    
    // 复制字符串内容
    strcpy(copy, s);
    
    return copy;
}

int get_place(char *key, char *data) {
    // 检查参数有效性
    if (key == NULL || data == NULL || *key == '\0' || *data == '\0') {
        return -1;
    }
    int length = strlen(key);
    
    // 复制data字符串，避免修改原字符串
    char *data_copy = strdup(data);
    if (data_copy == NULL) {
        return -1; // 内存分配失败
    }
    
    int position = 1;
    char *token = strtok(data_copy, ";");
    
    // 遍历所有逗号分隔的元素
    while (token != NULL) {
        // 比较当前元素与key
        if (strncmp(token, key, length) == 0) {
            free(data_copy);
            return position;
        }
        
        // 移动到下一个元素
        token = strtok(NULL, ";");
        position++;
    }
    
    // 未找到key
    free(data_copy);
    return 6;
}

int process_game_string(const char *input, char *output, size_t output_size) {
    if (input == NULL || output == NULL || output_size == 0) {
        return 0;
    }

    // 检查字符串是否以"GAME:"开头
    if (strncmp(input, "GAME:", 5) != 0) {
        return 0;
    }
    const char *rest = input + 5;

    // 分割各个部分
    char *part1, *part2, *part3, *part4;
    char *str_copy = strdup(rest);
    if (str_copy == NULL) {
        return 0;
    }

    // 分割出cards部分
    part1 = strtok(str_copy, ":");
    if (part1 == NULL) {
        free(str_copy);
        return 0;
    }

    // 分割出current_turn部分
    part2 = strtok(NULL, ":");
    if (part2 == NULL) {
        free(str_copy);
        return 0;
    }

    // 分割出step_count部分
    part3 = strtok(NULL, ":");
    if (part3 == NULL) {
        free(str_copy);
        return 0;
    }

    // 分割出device_ids部分
    part4 = strtok(NULL, ":");
    part4 = strtok(NULL, ":");
    part4 = strtok(NULL, ":");
    part4 = strtok(NULL, ":");    
    part4 = strtok(NULL, "");
    
    if (part4 == NULL) {
        free(str_copy);
        return 0;
    }
    device_role = get_place(device_id, part4);
    printf("%s(%d) -> %s\n", device_id, device_role, part2);

    // 处理cards部分：分割、取模13、排序
    int cards[54];  // 最多54张牌
    int card_count = 0;
    char *card_str = strdup(part1);
    if (card_str == NULL) {
        free(str_copy);
        return 0;
    }

    char *token = strtok(card_str, ",");
    while (token != NULL && card_count < 54) {
        // 转换为整数
        char *endptr;
        long val = strtol(token, &endptr, 10);
        if (*endptr == '\0' && val >= 1 && val <= 54) {
            // 取模13，注意13的倍数取模后为0，这里转为13
            if (val <= 52) {
                int mod_val = val % 13;
                cards[card_count++] = (mod_val == 0) ? 13 : mod_val;
            } else {
                cards[card_count++] = val;
            }
        }
        token = strtok(NULL, ",");
    }
    free(card_str);

    // 对处理后的牌进行排序
    qsort(cards, card_count, sizeof(int), compare_int);

    // 构建输出字符串
    int written = snprintf(output, output_size, "GAME:");
    if (written < 0 || (size_t)written >= output_size) {
        free(str_copy);
        return 0;
    }

    // 添加处理后的cards
    for (int i = 0; i < card_count; i++) {
        char temp[16];
        snprintf(temp, sizeof(temp), "%d%s", cards[i], (i < card_count - 1) ? "," : "");
        
        if (strlen(output) + strlen(temp) >= output_size) {
            free(str_copy);
            return 0;
        }
        strcat(output, temp);
    }

    // 添加剩余部分
    char temp[output_size - strlen(output)];
    snprintf(temp, sizeof(temp), ":%s:%s:%s", part2, part3, part4);
    
    if (strlen(output) + strlen(temp) >= output_size) {
        free(str_copy);
        return 0;
    }
    strcat(output, temp);

    free(str_copy);
    return 1;
}



// 生成随机设备ID
void generate_device_id() {
    const char *chars = "0123456789ABCDEF";
    srand(time(NULL) ^ getpid());
    for (int i = 0; i < DEVICE_ID_LEN - 1; i++) {
        device_id[i] = chars[rand() % 16];
    }
    device_id[DEVICE_ID_LEN - 1] = '\0';
}

void print_current_turn(const char *input, int start) {
    int length = strlen(input);
    
    printf("%s(%d) -> ", device_id, device_role);
    for (int i = start; i < length; i++) {
        if (input[i] == ':') {
            printf("\n");
            break;
        } else {
            printf("%c", input[i]);
        }
    }

}

// 接收消息线程
void *receive_thread() {
    char buffer[BUFFER_SIZE];
    char message[BUFFER_SIZE];
    int len;
    
    while (running) {
        len = recvfrom(sockfd, buffer, BUFFER_SIZE, 0, 
                      (struct sockaddr *)&server_addr, &server_len);
        if (len > 0) {
            buffer[len] = '\0';
            time_t now = time(NULL);
            struct tm *t = localtime(&now);
            char time_str[20];
            strftime(time_str, sizeof(time_str), "%H:%M:%S", t);
            
            if (strstr(buffer, "GAME:") == buffer) {
                if (process_game_string(buffer, message, sizeof(message)) == 1) {
                    printf("[%s] 收到消息: %s\n", time_str, message);
                } else {
                    printf("[%s] 收到消息: %s\n", time_str, buffer);
                }                
            } else if (strstr(buffer, "ACK:") == buffer) {
                print_current_turn(buffer, 4);
                printf("[%s] 收到消息: %s\n", time_str, buffer);
            } else if (strstr(buffer, "SYNC:") == buffer) {
                print_current_turn(buffer, 5);
                printf("[%s] 收到消息: %s\n", time_str, buffer);
            } else if (len > 2000) {

            } else if (len > 500) {
                printf("[%s] 收到语音\n", time_str);
            } else {
                printf("[%s] 收到消息: %s\n", time_str, buffer);
            }
        }
    }
    return NULL;
}

// 发送心跳线程
void *heartbeat_thread() {
    char buffer[BUFFER_SIZE];
    
    while (running) {
        snprintf(buffer, BUFFER_SIZE, "HEARTBEAT:%s", device_id);
        sendto(sockfd, buffer, strlen(buffer), 0,
              (struct sockaddr *)&server_addr, server_len);
        sleep(5); // 每5秒发送一次心跳
    }
    return NULL;
}

// 显示帮助信息
void print_help() {
    printf("命令列表:\n");
    printf("  start <2|4|6|8>    - 开始2人/4人/6人/8人游戏\n");
    printf("  reload         - 重新加载游戏状态\n");
    printf("  card num:value - 发送牌\n");
    printf("  skip           - 跳过\n");
    printf("  giveup         - 投降\n"); 
    printf("  change <name>  - 修改名称\n");
    printf("  send <msg>     - 发送自定义消息\n");
    printf("  help           - 显示帮助信息\n");
    printf("  exit           - 退出程序\n");
}

int main(int argc, char *argv[]) {
    pthread_t recv_tid, hb_tid;
    char input[BUFFER_SIZE];
    char cmd[32], arg[BUFFER_SIZE];
    
    // 生成设备ID
    if (argc > 1) {
        strcpy(device_id, argv[1]);
    } else {
        generate_device_id();
    }
    
    printf("当前设备ID: %s\n", device_id);
    
    // 创建UDP socket
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket创建失败");
        exit(EXIT_FAILURE);
    }
    
    // 初始化服务器地址
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    if (inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr) <= 0) {
        perror("无效的服务器IP");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    
    // 启动接收线程
    if (pthread_create(&recv_tid, NULL, receive_thread, NULL) != 0) {
        perror("创建接收线程失败");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    
    // 启动心跳线程
    if (pthread_create(&hb_tid, NULL, heartbeat_thread, NULL) != 0) {
        perror("创建心跳线程失败");
        close(sockfd);
        pthread_cancel(recv_tid);
        exit(EXIT_FAILURE);
    }
    
    print_help();
    
    // 命令输入循环
    while (running) {
        printf("> ");
        fflush(stdout);
        
        if (fgets(input, BUFFER_SIZE, stdin) == NULL) {
            break;
        }
        input[strcspn(input, "\n")] = '\0'; // 去除换行符
        
        if (sscanf(input, "%s %s", cmd, arg) >= 1) {
            if (strcmp(cmd, "start") == 0) {
                // 开始游戏
                int game_type;
                if (arg[0] != '\0') {
                    game_type = atoi(arg);
                }
                char buffer[BUFFER_SIZE];
                snprintf(buffer, BUFFER_SIZE, "START:%d:%s", game_type, device_id);
                sendto(sockfd, buffer, strlen(buffer), 0,
                      (struct sockaddr *)&server_addr, server_len);
                printf("已发送%d人游戏请求\n", game_type);
            }
            else if (strcmp(cmd, "reload") == 0) {
                // 重新加载
                char buffer[BUFFER_SIZE];
                snprintf(buffer, BUFFER_SIZE, "RELOAD:%s", device_id);
                sendto(sockfd, buffer, strlen(buffer), 0,
                      (struct sockaddr *)&server_addr, server_len);
                printf("已发送重新加载请求 %s\n", buffer);
            }
            else if (strcmp(cmd, "card") == 0) {
                // 发送牌
                if (arg[0] != '\0') {
                    int card_num;
                    int card_value;
                    if (sscanf(arg, "%d:%d", &card_num, &card_value) != 2) {
                        continue;
                    }                    
                    char buffer[BUFFER_SIZE];
                    snprintf(buffer, BUFFER_SIZE, "CARD:%d:%d:%s", card_num, card_value, device_id);
                    sendto(sockfd, buffer, strlen(buffer), 0,
                          (struct sockaddr *)&server_addr, server_len);
                    printf("已发送打牌请求\n");
                } else {
                    printf("请输入要发送的消息内容\n");
                }
            }
            else if (strcmp(cmd, "change") == 0) {
                // 发送牌
                if (arg[0] != '\0') {                    
                    strcpy(device_id, arg);
                    printf("已修改设备名\n");
                } else {
                    printf("请输入名称\n");
                }
            }
            else if (strcmp(cmd, "skip") == 0) {
                // 发送跳过
                char buffer[BUFFER_SIZE];
                snprintf(buffer, BUFFER_SIZE, "SKIP:%s", device_id);
                sendto(sockfd, buffer, strlen(buffer), 0,
                      (struct sockaddr *)&server_addr, server_len);
                printf("已发送跳过请求 %s\n", buffer);
            }
            else if (strcmp(cmd, "giveup") == 0) {
                // 发送投降
                char buffer[BUFFER_SIZE];
                snprintf(buffer, BUFFER_SIZE, "GIVEUP:%s", device_id);
                sendto(sockfd, buffer, strlen(buffer), 0,
                      (struct sockaddr *)&server_addr, server_len);
                printf("已发送投降请求 %s\n", buffer);
            }
            else if (strcmp(cmd, "send") == 0) {
                // 发送自定义消息
                if (arg[0] != '\0') {
                    sendto(sockfd, arg, strlen(arg), 0,
                          (struct sockaddr *)&server_addr, server_len);
                    printf("已发送消息: %s\n", arg);
                } else {
                    printf("请输入要发送的消息内容\n");
                }
            }
            else if (strcmp(cmd, "help") == 0) {
                print_help();
            }
            else if (strcmp(cmd, "exit") == 0) {
                running = 0;
                printf("正在退出...\n");
            }
            else {
                printf("未知命令，请输入help查看帮助\n");
            }
        }
    }
    
    // 清理资源
    pthread_cancel(recv_tid);
    pthread_cancel(hb_tid);
    pthread_join(recv_tid, NULL);
    pthread_join(hb_tid, NULL);
    close(sockfd);
    
    return 0;
}